package com.eztalks.paypal;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import org.junit.Test;

import com.paypal.api.payments.Agreement;
import com.paypal.api.payments.AgreementStateDescriptor;
import com.paypal.api.payments.ChargeModels;
import com.paypal.api.payments.Currency;
import com.paypal.api.payments.MerchantPreferences;
import com.paypal.api.payments.Patch;
import com.paypal.api.payments.Payer;
import com.paypal.api.payments.PaymentDefinition;
import com.paypal.api.payments.Plan;
import com.paypal.base.Constants;
import com.paypal.base.rest.APIContext;
import com.paypal.base.rest.PayPalRESTException;

public class SubscriptionSample {
	private static final String clientID = "AfcY59o_imV3VlN4VYpqH30gIfrhZ5WrY4GMyfZFvL94EXG_BQttwRrlkbgrfye6H3zgqFEV3e2brjUy";
	private static final String clientSecret = "EFX2Loz2VE-hdidZ5ktob8Aq4FqJJYFctFJKrhkKbPkLAnnjlkueix4-7MoHfz2V3KhPVTDJSyFMgzSC";

	protected Plan instance = null;

	/**
	 * Create a plan.
	 *
	 * https://developer.paypal.com/webapps/developer/docs/api/#create-a-plan
	 *
	 * @return newly created Plan instance
	 * @throws PayPalRESTException
	 */
	public Plan create(APIContext context) throws PayPalRESTException, IOException {
		// Build Plan object
		Plan plan = new Plan();
		plan.setName("T-Shirt of the Month Club Plan");
		plan.setDescription("Template creation.");
		plan.setType("fixed");

		// payment_definitions
		PaymentDefinition paymentDefinition = new PaymentDefinition();
		paymentDefinition.setName("Regular Payments");
		paymentDefinition.setType("REGULAR");
		paymentDefinition.setFrequency("DAY");
		paymentDefinition.setFrequencyInterval("1");
		paymentDefinition.setCycles("12");

		// currency
		Currency currency = new Currency();
		currency.setCurrency("USD");
		currency.setValue("20");
		paymentDefinition.setAmount(currency);

		// charge_models
		ChargeModels chargeModels = new com.paypal.api.payments.ChargeModels();
		chargeModels.setType("SHIPPING");
		chargeModels.setAmount(currency);
		List<ChargeModels> chargeModelsList = new ArrayList<ChargeModels>();
		chargeModelsList.add(chargeModels);
		paymentDefinition.setChargeModels(chargeModelsList);

		// payment_definition
		List<PaymentDefinition> paymentDefinitionList = new ArrayList<PaymentDefinition>();
		paymentDefinitionList.add(paymentDefinition);

		plan.setPaymentDefinitions(paymentDefinitionList);

		// merchant_preferences
		MerchantPreferences merchantPreferences = new MerchantPreferences();
		merchantPreferences.setSetupFee(currency);
		merchantPreferences.setCancelUrl("http://www.eztalks.com/cancel");// 取消授权的地址
		merchantPreferences.setReturnUrl("http://www.eztalks.com/return");// 授权成功之后的地址
		merchantPreferences.setMaxFailAttempts("2");
		merchantPreferences.setAutoBillAmount("YES");
		merchantPreferences.setInitialFailAmountAction("CANCEL");
		plan.setMerchantPreferences(merchantPreferences);

		this.instance = plan.create(context);
		return this.instance;
	}

	/**
	 * Update a plan
	 *
	 * https://developer.paypal.com/webapps/developer/docs/api/#update-a-plan
	 *
	 * @return updated Plan instance
	 * @throws PayPalRESTException
	 */
	public Plan update(APIContext context) throws PayPalRESTException, IOException {

		List<Patch> patchRequestList = new ArrayList<Patch>();
		Map<String, String> value = new HashMap<String, String>();
		value.put("state", "ACTIVE");

		Patch patch = new Patch();
		patch.setPath("/");
		patch.setValue(value);
		patch.setOp("replace");
		patchRequestList.add(patch);

		this.instance.update(context, patchRequestList);
		return this.instance;
	}

	/**
	 * Retrieve a plan
	 *
	 * https://developer.paypal.com/webapps/developer/docs/api/#retrieve-a-plan
	 *
	 * @return the retrieved plan
	 * @throws PayPalRESTException
	 */
	public Plan retrieve(APIContext context) throws PayPalRESTException {
		return Plan.get(context, this.instance.getId());
	}

	public Agreement createAgreement(APIContext context, String planId) throws Exception {
		Agreement agreement = new Agreement();
		agreement.setName("Standard");
		agreement.setDescription("Standard Plan for one month");

		TimeZone tz = TimeZone.getTimeZone("UTC");
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
		df.setTimeZone(tz);
		String nowAsISO = df.format(new Date());

		agreement.setStartDate(nowAsISO);

		Plan plan = new Plan();
		plan.setId(planId);
		agreement.setPlan(plan);

		Payer payer = new Payer();
		payer.setPaymentMethod("paypal");

		agreement.setPayer(payer);

		Agreement response = agreement.create(context);
		return response;
	}

	public Agreement executeAgreement(APIContext context, String agreemeId) throws Exception {
		Agreement agreement = Agreement.execute(context, agreemeId);
		return agreement;
	}

	@Test
	public void createPlanAndAgreement() {
		try {
			SubscriptionSample subscriptionSample = new SubscriptionSample();

			APIContext context = new APIContext(clientID, clientSecret, Constants.SANDBOX);

			// 创建plan
			Plan plan = subscriptionSample.create(context);
			System.out.println(plan);
			System.out.println("create response:\n" + Plan.getLastResponse());
			// 激活plan
			subscriptionSample.update(context);
			System.out.println("plan updated");
			// 创建agrement
			Agreement agreement = subscriptionSample.createAgreement(context, plan.getId());
			System.out.println(agreement);
			// 获取plan
			subscriptionSample.retrieve(context);
			System.out.println("retrieve response:\n" + Plan.getLastResponse());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Test
	public void bindAgreement() {
		try {
			SubscriptionSample subscriptionSample = new SubscriptionSample();
			APIContext context = new APIContext(clientID, clientSecret, Constants.SANDBOX);
			Agreement executeAgreement = subscriptionSample.executeAgreement(context, "EC-1MU041539A644562S");
			System.out.println(executeAgreement);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Test
	public void suspendAgreement() {
		try {
			APIContext context = new APIContext(clientID, clientSecret, Constants.SANDBOX);
			Agreement agreement = new Agreement();
			agreement.setId("I-XLFSJU32FGD5");

			AgreementStateDescriptor agreementStateDescriptor = new AgreementStateDescriptor();
			agreementStateDescriptor.setNote("suspend");
			agreement.suspend(context, agreementStateDescriptor);

		} catch (PayPalRESTException e) {
			e.printStackTrace();
		}
	}

	@Test
	public void reActiveAgreement() {
		try {
			APIContext context = new APIContext(clientID, clientSecret, Constants.SANDBOX);
			Agreement agreement = new Agreement();
			agreement.setId("I-XLFSJU32FGD5");
			AgreementStateDescriptor agreementStateDescriptor = new AgreementStateDescriptor();
			agreementStateDescriptor.setNote("reActivate");
			agreement.reActivate(context, agreementStateDescriptor);
		} catch (PayPalRESTException e) {
			e.printStackTrace();
		}
	}

	@Test
	public void cancelAgreement() {
		APIContext context = new APIContext(clientID, clientSecret, Constants.SANDBOX);

		Agreement agreement = new Agreement();
		agreement.setId("I-8MGKF5GM706F");
		try {
			AgreementStateDescriptor agreementStateDescriptor = new AgreementStateDescriptor();
			agreementStateDescriptor.setNote("upgrade");

			agreement.cancel(context, agreementStateDescriptor);
		} catch (PayPalRESTException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
